#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import xml.etree.ElementTree as ET

input_list = []


for arg in sys.argv[1:]:
    input_list.append(arg)

if len(input_list) < 1:
    print("usage: makedoku.py <classes.xml>")
    sys.exit(0)


def validate_tag(elem, tag):
    if (elem.tag != tag):
        print("Tag mismatch, expected '" + tag + "', got " + elem.tag)
        sys.exit(255)


class_names = []
classes = {}


def make_class_list(class_list, columns):

    f = open("class_list.txt", "wb")
    prev = 0
    col_max = len(class_list) / columns + 1
    print("col max is ", col_max)
    col_count = 0
    row_count = 0
    last_initial = ""
    fit_columns = []

    for n in range(0, columns):
        fit_columns += [[]]

    indexers = []
    last_initial = ""

    idx = 0
    for n in class_list:
        col = idx / col_max
        if (col >= columns):
            col = columns - 1
        fit_columns[col] += [n]
        idx += 1
        if (n[:1] != last_initial):
            indexers += [n]
        last_initial = n[:1]

    row_max = 0

    for n in range(0, columns):
        if (len(fit_columns[n]) > row_max):
            row_max = len(fit_columns[n])

    for r in range(0, row_max):
        s = "|"
        for c in range(0, columns):
            if (r >= len(fit_columns[c])):
                continue

            classname = fit_columns[c][r]
            initial = classname[0]
            if (classname in indexers):
                s += "**" + initial + "**|"
            else:
                s += " |"

            s += "[[" + classname.lower() + "|" + classname + "]]|"

        s += "\n"
        f.write(s)


def dokuize_text(txt):

    return txt


def dokuize_text(text):
    pos = 0
    while(True):
        pos = text.find("[", pos)
        if (pos == -1):
            break

        endq_pos = text.find("]", pos + 1)
        if (endq_pos == -1):
            break

        pre_text = text[:pos]
        post_text = text[endq_pos + 1:]
        tag_text = text[pos + 1:endq_pos]

        if (tag_text in class_names):
            tag_text = "[[" + tag_text.lower() + "|" + tag_text + "]]"
        else:  # command
            cmd = tag_text
            space_pos = tag_text.find(" ")
            if (cmd.find("html") == 0):
                cmd = tag_text[:space_pos]
                param = tag_text[space_pos + 1:]
                tag_text = "<" + param + ">"
            elif(cmd.find("method") == 0):
                cmd = tag_text[:space_pos]
                param = tag_text[space_pos + 1:]

                if (param.find(".") != -1):
                    class_param, method_param = param.split(".")
                    tag_text = "[[" + class_param.lower() + "#" + method_param + "|" + class_param + '.' + method_param + "]]"
                else:
                    tag_text = "[[#" + param + "|" + param + "]]"
            elif (cmd.find("image=") == 0):
                tag_text = "{{" + cmd[6:] + "}}"
            elif (cmd.find("url=") == 0):
                tag_text = "[[" + cmd[4:] + "|"
            elif (cmd == "/url"):
                tag_text = "]]>"
            elif (cmd == "center"):
                tag_text = ""
            elif (cmd == "/center"):
                tag_text = ""
            elif (cmd == "br"):
                tag_text = "\\\\\n"
            elif (cmd == "i" or cmd == "/i"):
                tag_text = "//"
            elif (cmd == "b" or cmd == "/b"):
                tag_text = "**"
            elif (cmd == "u" or cmd == "/u"):
                tag_text = "__"
            else:
                tag_text = "[" + tag_text + "]"

        text = pre_text + tag_text + post_text
        pos = len(pre_text) + len(tag_text)

    #tnode = ET.SubElement(parent,"div")
    # tnode.text=text
    return text


def make_type(t):
    global class_names
    if (t in class_names):
        return "[[" + t.lower() + "|" + t + "]]"
    return t


def make_method(f, name, m, declare, event=False):

    s = "  * "
    ret_type = "void"
    args = list(m)
    mdata = {}
    mdata["argidx"] = []
    for a in args:
        if (a.tag == "return"):
            idx = -1
        elif (a.tag == "argument"):
            idx = int(a.attrib["index"])
        else:
            continue

        mdata["argidx"].append(idx)
        mdata[idx] = a

    if (not event):
        if (-1 in mdata["argidx"]):
            s += make_type(mdata[-1].attrib["type"])
        else:
            s += "void"
        s += " "

    if (declare):

        # span.attrib["class"]="funcdecl"
        # a=ET.SubElement(span,"a")
        # a.attrib["name"]=name+"_"+m.attrib["name"]
        # a.text=name+"::"+m.attrib["name"]
        s += "**" + m.attrib["name"] + "**"
    else:
        s += "[[#" + m.attrib["name"] + "|" + m.attrib["name"] + "]]"

    s += "**(**"
    argfound = False
    for a in mdata["argidx"]:
        arg = mdata[a]
        if (a < 0):
            continue
        if (a > 0):
            s += ", "
        else:
            s += " "

        s += make_type(arg.attrib["type"])
        if ("name" in arg.attrib):
            s += " " + arg.attrib["name"]
        else:
            s += " arg" + str(a)

        if ("default" in arg.attrib):
            s += "=" + arg.attrib["default"]

        argfound = True

    if (argfound):
        s += " "
    s += "**)**"

    if ("qualifiers" in m.attrib):
        s += " " + m.attrib["qualifiers"]

    f.write(s + "\n")


def make_doku_class(node):

    name = node.attrib["name"]

    f = open(name.lower() + ".txt", "wb")

    f.write("======  " + name + "  ======\n")

    if ("inherits" in node.attrib):
        inh = node.attrib["inherits"].strip()
        f.write("**Inherits:** [[" + inh.lower() + "|" + inh + "]]\\\\\n")
    if ("category" in node.attrib):
        f.write("**Category:** " + node.attrib["category"].strip() + "\\\\\n")

    briefd = node.find("brief_description")
    if (briefd != None):
        f.write("=====  Brief Description  ======\n")
        f.write(dokuize_text(briefd.text.strip()) + "\n")

    methods = node.find("methods")

    if(methods != None and len(list(methods)) > 0):
        f.write("=====  Member Functions  ======\n")
        for m in list(methods):
            make_method(f, node.attrib["name"], m, False)

    events = node.find("signals")
    if(events != None and len(list(events)) > 0):
        f.write("=====  Signals  ======\n")
        for m in list(events):
            make_method(f, node.attrib["name"], m, True, True)

    members = node.find("members")

    if(members != None and len(list(members)) > 0):
        f.write("=====  Member Variables  ======\n")

        for c in list(members):
            s = "  * "
            s += make_type(c.attrib["type"]) + " "
            s += "**" + c.attrib["name"] + "**"
            if (c.text.strip() != ""):
                s += " - " + c.text.strip()
            f.write(s + "\n")

    constants = node.find("constants")
    if(constants != None and len(list(constants)) > 0):
        f.write("=====  Numeric Constants  ======\n")
        for c in list(constants):
            s = "  * "
            s += "**" + c.attrib["name"] + "**"
            if ("value" in c.attrib):
                s += " = **" + c.attrib["value"] + "**"
            if (c.text.strip() != ""):
                s += " - " + c.text.strip()
            f.write(s + "\n")

    descr = node.find("description")
    if (descr != None and descr.text.strip() != ""):
        f.write("=====  Description  ======\n")
        f.write(dokuize_text(descr.text.strip()) + "\n")

    methods = node.find("methods")

    if(methods != None and len(list(methods)) > 0):
        f.write("=====  Member Function Description  ======\n")
        for m in list(methods):

            d = m.find("description")
            if (d == None or d.text.strip() == ""):
                continue
            f.write("==  " + m.attrib["name"] + "  ==\n")
            make_method(f, node.attrib["name"], m, False)
            f.write("\\\\\n")
            f.write(dokuize_text(d.text.strip()))
            f.write("\n")

    """
  div=ET.Element("div")
  div.attrib["class"]="class";

  a=ET.SubElement(div,"a")
  a.attrib["name"]=node.attrib["name"]

  h3=ET.SubElement(a,"h3")
  h3.attrib["class"]="title class_title"
  h3.text=node.attrib["name"]

  briefd = node.find("brief_description")
  if (briefd!=None):
   div2=ET.SubElement(div,"div")
   div2.attrib["class"]="description class_description"
   div2.text=briefd.text

  if ("inherits" in node.attrib):
   ET.SubElement(div,"br")

   div2=ET.SubElement(div,"div")
   div2.attrib["class"]="inheritance";

   span=ET.SubElement(div2,"span")
   span.text="Inherits: "

   make_type(node.attrib["inherits"],div2)

  if ("category" in node.attrib):
   ET.SubElement(div,"br")

   div3=ET.SubElement(div,"div")
   div3.attrib["class"]="category";

   span=ET.SubElement(div3,"span")
   span.attrib["class"]="category"
   span.text="Category: "

   a = ET.SubElement(div3,"a")
   a.attrib["class"]="category_ref"
   a.text=node.attrib["category"]
   catname=a.text
   if (catname.rfind("/")!=-1):
    catname=catname[catname.rfind("/"):]
   catname="CATEGORY_"+catname

   if (single_page):
    a.attrib["href"]="#"+catname
   else:
    a.attrib["href"]="category.html#"+catname


  methods = node.find("methods")

  if(methods!=None and len(list(methods))>0):

   h4=ET.SubElement(div,"h4")
   h4.text="Public Methods:"

   method_table=ET.SubElement(div,"table")
   method_table.attrib["class"]="method_list";

   for m in list(methods):
#    li = ET.SubElement(div2, "li")
    method_table.append( make_method_def(node.attrib["name"],m,False) )

  events = node.find("signals")

  if(events!=None and len(list(events))>0):
   h4=ET.SubElement(div,"h4")
   h4.text="Events:"

   event_table=ET.SubElement(div,"table")
   event_table.attrib["class"]="method_list";

   for m in list(events):
#    li = ET.SubElement(div2, "li")
    event_table.append( make_method_def(node.attrib["name"],m,False,True) )


  members = node.find("members")
  if(members!=None and len(list(members))>0):

   h4=ET.SubElement(div,"h4")
   h4.text="Public Variables:"
   div2=ET.SubElement(div,"div")
   div2.attrib["class"]="member_list";

   for c in list(members):

    li = ET.SubElement(div2, "li")
    div3=ET.SubElement(li,"div")
    div3.attrib["class"]="member";
    make_type(c.attrib["type"],div3)
    span=ET.SubElement(div3,"span")
    span.attrib["class"]="identifier member_name"
    span.text=" "+c.attrib["name"]+" "
    span=ET.SubElement(div3,"span")
    span.attrib["class"]="member_description"
    span.text=c.text


  constants = node.find("constants")
  if(constants!=None and len(list(constants))>0):

   h4=ET.SubElement(div,"h4")
   h4.text="Constants:"
   div2=ET.SubElement(div,"div")
   div2.attrib["class"]="constant_list";

   for c in list(constants):
    li = ET.SubElement(div2, "li")
    div3=ET.SubElement(li,"div")
    div3.attrib["class"]="constant";

    span=ET.SubElement(div3,"span")
    span.attrib["class"]="identifier constant_name"
    span.text=c.attrib["name"]+" "
    if ("value" in c.attrib):
     span=ET.SubElement(div3,"span")
     span.attrib["class"]="symbol"
     span.text="= "
     span=ET.SubElement(div3,"span")
     span.attrib["class"]="constant_value"
     span.text=c.attrib["value"]+" "
    span=ET.SubElement(div3,"span")
    span.attrib["class"]="constant_description"
    span.text=c.text

#  ET.SubElement(div,"br")


  descr=node.find("description")
  if (descr!=None and descr.text.strip()!=""):

   h4=ET.SubElement(div,"h4")
   h4.text="Description:"

   make_text_def(node.attrib["name"],div,descr.text)
#   div2=ET.SubElement(div,"div")
#   div2.attrib["class"]="description";
#   div2.text=descr.text



  if(methods!=None or events!=None):

   h4=ET.SubElement(div,"h4")
   h4.text="Method Documentation:"
   iter_list = []
   if (methods!=None):
    iter_list+=list(methods)
   if (events!=None):
    iter_list+=list(events)

   for m in iter_list:

    descr=m.find("description")

    if (descr==None or descr.text.strip()==""):
     continue;

    div2=ET.SubElement(div,"div")
    div2.attrib["class"]="method_doc";


    div2.append( make_method_def(node.attrib["name"],m,True) )
	#anchor = ET.SubElement(div2, "a")
	#anchor.attrib["name"] =
    make_text_def(node.attrib["name"],div2,descr.text)
    #div3=ET.SubElement(div2,"div")
    #div3.attrib["class"]="description";
    #div3.text=descr.text


  return div
"""
for file in input_list:
    tree = ET.parse(file)
    doc = tree.getroot()

    if ("version" not in doc.attrib):
        print("Version missing from 'doc'")
        sys.exit(255)

    version = doc.attrib["version"]

    for c in list(doc):
        if (c.attrib["name"] in class_names):
            continue
        class_names.append(c.attrib["name"])
        classes[c.attrib["name"]] = c


class_names.sort()

make_class_list(class_names, 4)

for cn in class_names:
    c = classes[cn]
    make_doku_class(c)
